package org.dromara.common.sensitive.handler

import com.fasterxml.jackson.core.JsonGenerator
import com.fasterxml.jackson.databind.BeanProperty
import com.fasterxml.jackson.databind.JsonMappingException
import com.fasterxml.jackson.databind.JsonSerializer
import com.fasterxml.jackson.databind.SerializerProvider
import com.fasterxml.jackson.databind.ser.ContextualSerializer
import io.github.oshai.kotlinlogging.KotlinLogging
import org.dromara.common.core.utils.SpringUtils
import org.dromara.common.sensitive.annotation.Sensitive
import org.dromara.common.sensitive.core.SensitiveService
import org.dromara.common.sensitive.core.SensitiveStrategy
import org.springframework.beans.BeansException
import java.io.IOException

/**
 * 数据脱敏json序列化工具
 *
 * @author LikeYouDo
 */

class SensitiveHandler : JsonSerializer<String>(), ContextualSerializer {
    companion object {
        private val log = KotlinLogging.logger { }
    }

    private lateinit var strategy: SensitiveStrategy
    private lateinit var roleKey: Array<String>
    private lateinit var perms: Array<String>

    @Throws(IOException::class)
    override fun serialize(value: String, gen: JsonGenerator, serializers: SerializerProvider?) {
        try {
            val sensitiveService: SensitiveService? =
                SpringUtils.getBean(SensitiveService::class.java)
            if (sensitiveService != null && sensitiveService.isSensitive(roleKey, perms)) {
                gen.writeString(strategy.desensitizer().apply(value))
            } else {
                gen.writeString(value)
            }
        } catch (e: BeansException) {
            log.error { "脱敏实现不存在, 采用默认处理 => ${e.message}" }
            gen.writeString(value)
        }
    }

    @Throws(JsonMappingException::class)
    override fun createContextual(prov: SerializerProvider, property: BeanProperty): JsonSerializer<*> {
        val annotation = property.getAnnotation(Sensitive::class.java)
        if (annotation != null && String::class.java == property.type.rawClass) {
            this.strategy = annotation.strategy
            this.roleKey = annotation.roleKey
            this.perms = annotation.perms
            return this
        }
        return prov.findValueSerializer(property.type, property)
    }
}
